package rpg.manager
{
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	import rpg.Utils.AStar;
	import rpg.Utils.CharVal;
	import rpg.Utils.FPS;
	import rpg.Utils.GameUtils;
	import rpg.Utils.Print;
	import rpg.Utils.Val;
	import rpg.entity.Map;
	import rpg.interfaces.IUpdate;

	public class SceneManager
	{
		private static var instance:SceneManager
		private var stage:Stage;
		private var gm:GameManager;
		/**
		 * 场景id
		 */
		private var _mapId:int;

		public var map:Map;
		/**
		 * 游戏时间
		 */
		private var gameTime:int;
		private var gameTotalTime:int;
		/**
		 * 更新间隔
		 */
		private var delay:int;


		private var keyManager:KeyManager

		private var scene:Sprite;

		/**
		 * 高,中,低 3个级别的更新队列
		 */
		private var highUpdatables : Array = [];
		private var middenUpdatables : Array = [];
		private var lowUpdatables : Array = [];
		
		public function SceneManager()
		{
		}

		public static function getInstance():SceneManager
		{
			if (instance == null)
			{
				instance=new SceneManager();
			}
			return instance;
		}

		/**
		 * 必须初始化
		 * @param stage
		 *
		 */
		public function init(stage:Stage):void
		{
			this.stage=stage;
			this.stage.frameRate=GameUtils.frameRate;
			this.scene=new Sprite();
			this.stage.addChildAt(scene,0);
			this.keyManager=KeyManager.getInstance();
			this.gm=GameManager.getInstance();
			this.gm.init();
			GameUtils.stage=scene;

			//排列顺序,地图,人物,UI,TIP
			this.scene.addChild(gm.getContainer());
			this.scene.addChild(UIManager.getContainer());
			this.scene.addChild(TipManager.getContainer());
			this.gameTime=getTimer();
			this.addListener();
			this.stage.scaleMode=StageScaleMode.NO_SCALE;
			this.stage.align=StageAlign.TOP_LEFT;
		}

		public function addListener():void
		{
			this.stage.addEventListener(Event.RESIZE, onStageResize);
			this.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			this.scene.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
			this.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			this.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
		}

		private function onKeyDown(evt:KeyboardEvent):void
		{
			gm.onKeyDown(evt.keyCode);
			keyManager.onKeyDown(evt.keyCode);
		}

		private function onKeyUp(evt:KeyboardEvent):void
		{
			keyManager.onKeyUp(evt.keyCode);
		}

		public function onEnterFrame(evt:Event):void
		{
			delay=getTimer() - gameTime;
			gameTime=getTimer();
			gameTotalTime+=delay;
			gm.update(delay);
			
			update(delay);
		}

		public function onMouseMove(evt:MouseEvent):void
		{
			gm.onMouseMove(evt);
		}

		public function onStageResize(evt:Event):void
		{
			var changeWidth:int=stage.stageWidth - GameUtils.stageWidth;
			var changeHeight:int=stage.stageHeight - GameUtils.stageHeight;
			if (stage.stageWidth == 0 || stage.stageHeight == 0)
			{
				return;
			}

			if (map)
				map.resize(stage.stageWidth, stage.stageHeight);

			GameUtils.stageWidth=stage.stageWidth;
			GameUtils.stageHeight=stage.stageHeight;
			Print.init(stage);
			gm.updateWalkRectangle(changeWidth / 2, changeHeight / 2);
		}

		/**
		 * 重置窗口大小
		 * @param sizeInfo
		 *
		 */
		public function resizeWindows(sizeInfo:String):void
		{
			if (sizeInfo == CharVal.AUTOSWF)
			{
				if (ExternalInterface.available)
					var obj:Object=ExternalInterface.call('resizeSwf', '100%', '100%');
			}
			else
			{
				var temp:Array=sizeInfo.split('*');
				var width:int=int(temp[0]);
				var height:int=int(temp[1]);
				if (ExternalInterface.available)
				{
					ExternalInterface.call('resizeSwf', width + 'px', height + 'px');
				}
			}
		}

		public function get mapId():int
		{
			return _mapId;
		}

		public function set mapId(value:int):void
		{
			_mapId=value;
			if (map == null)
				map=new Map();
			map.mapId=_mapId;
			this.scene.addChildAt(map.mapBD, 0);
		}

		private var checkPoint:Point=new Point();

		public function checkisMask(x:Number, y:Number):Boolean
		{
			checkPoint.x=x;
			checkPoint.y=y;
			return map.maskSprite.getObjectsUnderPoint(checkPoint).length > 0;
		}
		
		
		/**
		 * 更新队列
		 * @param value
		 *
		 */
		public function update(value : int) : void
		{
			var i : int;
			var len : int = highUpdatables.length;
			
			for(i = len - 1; i >= 0; i -= 1)
			{
				if(highUpdatables[i] == null)
					continue;
				
				if(!highUpdatables[i].checkUpdatable(value) || lowUpdatables[i].isDestroy)
					continue;
				highUpdatables[i].update(value);
			}
			len = middenUpdatables.length;
			
			for(i = len - 1; i >= 0; i -= 1)
			{
				if(middenUpdatables[i] == null)
					continue;
				
				if(!middenUpdatables[i].checkUpdatable(value) || lowUpdatables[i].isDestroy)
					continue;
				middenUpdatables[i].update(value);
			}
			len = lowUpdatables.length;
			
			for(i = len - 1; i >= 0; i -= 1)
			{
				if(lowUpdatables[i] == null)
					continue;
				
				if(!lowUpdatables[i].checkUpdatable(value) || lowUpdatables[i].isDestroy)
					continue;
				lowUpdatables[i].update(value);
			}
			
		}
		
		/**
		 * 添加更新列表
		 * @param update   更新对象
		 * @param level    更新的等级,0低级,1中级,2高级
		 * @param priority 优先级
		 *
		 */
		public function addUpdate(update : IUpdate, registerdLevel : int = 0, priority : int = 0) : Boolean
		{
			var updatableArray : Array;
			
			switch(registerdLevel)
			{
				case Val.PRIORITY_HIGH:
					updatableArray = highUpdatables;
					break;
				case Val.PRIORITY_MIDDEN:
					updatableArray = middenUpdatables;
					break;
				case Val.PRIORITY_LOW:
					updatableArray = lowUpdatables;
					break;
			}
			
			if(updatableArray == null)
				return false;
			var index : int = updatableArray.indexOf(update);
			
			if(index != -1)
				return false;
			update.priority = priority;
			updatableArray.push(update);
			updatableArray.sortOn("priority", Array.NUMERIC | Array.DESCENDING);
			return true;
		}
		
		public function removeUpdate(update : IUpdate, registerdLevel : int) : Boolean
		{
			var updatableArray : Array;
			
			switch(registerdLevel)
			{
				case Val.PRIORITY_HIGH:
					updatableArray = highUpdatables;
					break;
				case Val.PRIORITY_MIDDEN:
					updatableArray = middenUpdatables;
					break;
				
				case Val.PRIORITY_LOW:
					updatableArray = lowUpdatables;
					break;
			}
			
			if(updatableArray == null)
				return false;
			var index : int = updatableArray.indexOf(update);
			
			if(index == -1)
				return false;
			updatableArray.splice(index, 1);
			return true;
		}
	}
}